package bsh.dyn;

import org.objectweb.asm.MethodVisitor;

import bsh.CompilationState;
import bsh.CompiledScript;
import bsh.exception.CompilationFailedException;

/**
 * A {@link TransformationList} that is unmodifiable. Works like an unmodifiable linked list of {@link Transformation}'s
 * 
 * @author takeshi
 */
public class UnmodifiableTransformationList implements TransformationList {
    private final Transformation transformation;

    private final TransformationList previous;

    /**
     * C'tor
     * 
     * @param transformation the current {@link Transformation}
     * @param previous the previous transformations
     */
    public UnmodifiableTransformationList(Transformation transformation, TransformationList previous) {
        this.transformation = transformation;
        this.previous = previous;
    }

    /**
     * {@inheritDoc}
     */
    public int getWeight() {
        if (previous.getWeight() == Integer.MAX_VALUE || transformation.getWeight() == Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        }
        return previous.getWeight() + transformation.getWeight();
    }

    /**
     * {@inheritDoc}
     */
    public TransformationList appendTransformation(Transformation tx) {
        return new UnmodifiableTransformationList(tx, this);
    }

    /**
     * {@inheritDoc}
     */
    public ActualParameter getTransformationTarget() {
        return this.transformation.getTransformationTarget();
    }

    /**
     * {@inheritDoc}
     */
    public boolean acceptsType(ActualParameter parameter) {
        return this.previous.acceptsType(parameter);
    }

    /**
     * {@inheritDoc}
     */
    public Object transform(Object object, CompiledScript script) {
        return this.transformation.transform(this.previous.transform(object, script), script);
    }

    /**
     * {@inheritDoc}
     */
    public boolean isCompilable() {
        return this.transformation.isCompilable() && this.previous.isCompilable();
    }

    /**
     * {@inheritDoc}
     */
    public void compile(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        if (this.transformation.isCompilable() && this.previous.isCompilable()) {
            this.previous.compile(visitor, state);
            ((CompilableTransformation) this.transformation).compile(visitor, state);
        } else {
            throw new IllegalArgumentException("not compilable!");
        }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return "UnmodifiableTransformationList [previous=" + previous + ", transformation=" + transformation + "]";
    }
}